<!--
 * @copyright: Huang Ding
 * @Author: ding-cx
 * @Date: 2021-03-11 17:46:36
 * @LastEditors: ding-cx
 * @LastEditTime: 2021-03-16 17:56:40
 * @Description: 权限选择组件封装面板。
-->
 <template>
  <el-row :gutter="10">
    <el-col :span="8">
      <el-card shadow="never">
        <div slot="header">
          菜单权限

          <el-tooltip
            effect="dark"
            content="注意：菜单设置权限时，需同时勾上其所有上级节点才可生效。"
            placement="right"
          >
            <i class="el-icon-warning"></i>
          </el-tooltip>
        </div>
        <div>
          <el-scrollbar
            :style="{ height: treeHeight }"
            wrap-class="scrollbar-wrapper"
          >
            <!-- <el-alert type="success" :closable="false">
              注意：勾选某个菜单之前，需同时勾上所有父级节点。
            </el-alert> -->
            <el-tree
              ref="treeRef"
              :data="tree.data"
              :props="tree.props"
              node-key="route_id"
              :filter-node-method="tree.filterNode"
              :expand-on-click-node="false"
              :check-strictly="true"
              :check-on-click-node="false"
              default-expand-all
              highlight-current
              show-checkbox=""
              @node-contextmenu="tree.nodeContextMenu"
              @node-click="tree.nodeClick"
              @check-change="tree.checkChange"
              @check="tree.check"
            >
              <!-- draggable -->
              <span
                class="custom-tree-node"
                style="font-size: 14px"
                slot-scope="{ node, data }"
              >
                <span v-if="!data.meta.icon" class="el-icon-plus"></span>
                <span
                  v-else-if="data.meta.icon.includes('el-icon')"
                  :class="data.meta.icon"
                >
                </span>
                <svg-icon v-else :icon-class="data.meta.icon" />
                <span style="display: inline-block; margin-left: 8px">{{
                  data.route_id + data.meta.title
                }}</span>
              </span>
            </el-tree>
          </el-scrollbar>
        </div>
      </el-card>
    </el-col>
    <el-col :span="8">
      <el-card shadow="never">
        <div slot="header">通用功能权限</div>
        <div>
          <el-scrollbar
            :style="{ height: treeHeight }"
            wrap-class="scrollbar-wrapper"
          >
            <div>
              <el-checkbox
                :indeterminate="common.isIndeterminate"
                v-model="common.checkAll"
                @change="common2.handleCheckAllChange"
                class="common-checkbox"
                :disabled="common.allDisabled"
                >全选</el-checkbox
              >
              <div style="height: 20px"></div>
              <el-checkbox-group v-model="common.checkedGroup">
                <!-- @change="common2.checkboxGroupChange" -->
                <el-checkbox
                  class="common-checkbox"
                  v-for="item in common2.funcList"
                  :label="item.value"
                  :key="item.value"
                  :disabled="common.allDisabled"
                  >{{ item.label }}</el-checkbox
                >
              </el-checkbox-group>
            </div>
          </el-scrollbar>
        </div>
      </el-card>
    </el-col>
    <el-col :span="8">
      <el-card shadow="never">
        <div slot="header">自定义功能权限</div>
        <div>
          <el-scrollbar
            :style="{ height: treeHeight }"
            wrap-class="scrollbar-wrapper"
          >
            <div>
              <el-checkbox-group v-model="custom.checkedGroup">
                <!-- @change="common2.checkboxGroupChange" -->
                <!-- <el-tooltip
                  effect="dark"
                  v-for="item in custom.custom_perm_list"
                  :content="item.cname + '[' + item.ename + ']'"
                  placement="right"
                  :key="item.id"
                > -->
                <el-checkbox
                  v-for="item in custom.custom_perm_list"
                  class="common-checkbox"
                  :label="item.id"
                  :key="item.id"
                  >{{ item.cname + "[" + item.ename + "]" }}</el-checkbox
                >
                <!-- </el-tooltip> -->
              </el-checkbox-group>
            </div>
          </el-scrollbar>
        </div>
      </el-card>
    </el-col>

    <!-- <el-col :span="24">
      <div>选中的菜单id：{{ selectedRouteList }}</div>
    </el-col> -->
  </el-row>
</template>
 
 <script>
import {
  getCurrentInstance,
  ref,
  reactive,
  watch,
  computed,
  inject,
} from "@vue/composition-api";

import svs_sys_menus from "@/service/sys/menus";
import svs_sys_perm from "@/service/sys/permission";

const events = {
  menu_tree_check: "menu_tree_check", //菜单树check触发
  menu_tree_click: "menu_tree_click", //菜单树点击触发
  common_check: "common_check", //通用功能check触发
  custom_check: "custom_check", //自定义权限check触发
  set_checkedList: "set_checkedList", //设置选中的项目事件，由外部调用，内部接收后再触发。
};

function useEnter(setups) {
  const trees = useLeftTree(setups);
  const commons = useCommon(setups);
  const interfaces = useInterface(setups);
  const customs = useCustom(setups);

  return {
    ...trees,
    ...commons,
    ...interfaces,
    ...customs,
  };
}

/** 供外部调用的接口 */
function useInterface(setups) {
  const msg = inject("globalMessage");
  const dataList = reactive({
    menusList: [],
    commonList: {},
    customList: {},
  });
  // 选中的菜单，响应内部事件
  setups.that.$on(events.menu_tree_check, (data) => {
    dataList.menusList = data;
    setups.ctx.emit("check", dataList); //发送外部。
  });

  setups.that.$on(events.common_check, (data) => {
    dataList.commonList = data;
    setups.ctx.emit("check", dataList);
  });

  setups.that.$on(events.custom_check, (data) => {
    dataList.customList = data;
    setups.ctx.emit("check", dataList);
  });

  /** 设置选中项列表 data格式为dataList的对象格式。*/
  const setCheckedList = (data) => {
    data.menusList && (dataList.menusList = data.menusList);
    data.customList && (dataList.customList = data.customList);
    data.commonList && (dataList.commonList = data.commonList);

    setups.that.$emit(events.set_checkedList, data);
  };

  /** 清空所有选中项 */
  const empty = () => {
    setCheckedList({
      menusList: [],
      commonList: {},
      customList: {},
    });
  };

  /** 获取勾选的数据汇总 */
  const getDataList = () => {
    return dataList;
  };

  // 内部封装处理保存权限记录。外部传入角色的id list []即可。
  const handleSave = async (roleList = []) => {
    if (dataList.menusList.length < 1) {
      msg.emptyWarning();
      return;
    }

    const sendData = {
      roleIdList: roleList, //[]
      menusList: dataList.menusList, //[]
      commonList: dataList.commonList,
      customList: dataList.customList,
    };

    return svs_sys_perm.batchSetRolePermission(sendData).then((res) => {
      console.log(res);
      if (res.insertRows > 0) {
        msg.saveSuccess();
      }
      return res;
    });
  };

  return {
    getDataList,
    handleSave,
    setCheckedList,
    empty,
  };
}

/** 菜单树功能 */
function useLeftTree(setups) {
  const treeRef = ref(null);
  const tree = reactive({
    data: [],
    props: {
      label: "title",
      children: "children",
    },
    filterMsg: "",
  });

  // 获取数据
  svs_sys_menus.getRouteMenuTree().then((data) => {
    console.log(data);
    tree.data = data;
  });

  // 实现过滤功能。
  watch(
    () => tree.filterMsg,
    (nv, ov) => {
      // console.log(nv);
      treeRef.value.filter(nv);
    }
  );

  /** 树节点过滤 */
  tree.filterNode = (value, data) => {
    if (!value) return true;
    return data.title.indexOf(value) !== -1;
  };

  // 递归获取一个树的所有route_id
  function getNodeRouteId(node, getList = []) {
    getList.push(node.route_id);
    if (node.children && node.children.length > 0) {
      node.children.forEach((item) => {
        getNodeRouteId(item, getList);
      });
    }
  }

  /** 树节点点击 */
  tree.nodeClick = (node) => {
    // console.log(node);
    setups.that.$emit(events.menu_tree_click, node);
  };

  const treeHeight = computed(() => {
    return window.hei.value - 430 + "px";
  });

  // 节点右键点击
  tree.nodeContextMenu = (event, nodeObj, node, nodeComponent) => {
    // console.log(event);
    // console.log(nodeObj);
  };

  // 树节点checkbodx选中事件
  tree.checkChange = (nodeObj) => {};

  // 复选框被点击时触发
  tree.check = (nodeObj, checkedListObj) => {
    // console.log(nodeObj, checkedListObj);
    //  点击复选框选中时，自动把父级id勾选上
    if (checkedListObj.checkedKeys.includes(nodeObj.route_id)) {
      if (nodeObj.trees) {
        // console.log(nodeObj.trees.slice(0, nodeObj.trees.length - 1));
        checkedListObj.checkedKeys.push(
          ...nodeObj.trees.slice(0, nodeObj.trees.length - 1)
        );
        treeRef.value.setCheckedKeys(checkedListObj.checkedKeys);
      }
    }

    setups.that.$nextTick(() => {
      // selectedRouteList.value = treeRef.value.getCheckedKeys();
      // console.log(treeRef.value.getHalfCheckedKeys());
      setups.that.$emit(events.menu_tree_check, treeRef.value.getCheckedKeys());
    });
  };

  /** 响应外部设置勾选。 */
  setups.that.$on(events.set_checkedList, (data) => {
    const menus = data.menusList;
    // console.log(menus);
    if (Array.isArray(menus)) {
      treeRef.value.setCheckedKeys(menus);
      treeRef.value.setCurrentKey(null);
    }
  });

  return {
    tree,
    treeRef,
    treeHeight,
  };
}

/** 通用功能权限card的功能 */
function useCommon(setups) {
  // 全选功能
  const handleCheckAllChange = (val) => {
    // console.log(val);
    if (val) {
      common.checkedGroup = funcList.map((item) => item.value);
      common.isIndeterminate = false;
      common.checkAll = true;
    } else {
      common.checkedGroup = [];
      common.isIndeterminate = false;
      common.checkAll = false;
    }
  };

  // 复选框组change
  const checkboxGroupChange = (val) => {
    // console.log(val);
    if (val.length === 0) {
      common.isIndeterminate = false;
      common.checkAll = false;
    } else if (val.length < funcList.length) {
      common.isIndeterminate = true;
    } else {
      common.isIndeterminate = false;
      common.checkAll = true;
    }
  };

  const temp_menuCommonList = ref({});
  const temp_currentMenuId = ref(0); //缓存当前点击的菜单的id
  // 监听左侧菜单树node click事件
  setups.that.$on(events.menu_tree_click, (node) => {
    // console.log(node);
    if (node.children) {
      common.allDisabled = true;
    } else {
      common.allDisabled = false;
      temp_currentMenuId.value = node.route_id;
      common.checkedGroup =
        temp_menuCommonList.value[temp_currentMenuId.value] || [];
    }
  });

  const common = reactive({
    isIndeterminate: false,
    checkAll: false,
    allDisabled: true,
    checkedGroup: [],
  });

  watch(
    () => common.checkedGroup,
    (nv) => {
      if (temp_currentMenuId.value) {
        temp_menuCommonList.value[temp_currentMenuId.value] = nv;
        // 触发事件
        setups.that.$emit(events.common_check, temp_menuCommonList);
      }
      checkboxGroupChange(nv);
      // console.log(temp_menuCommonList.value);
    }
  );

  setups.that.$on(events.set_checkedList, (data) => {
    const checked = data.commonList;
    if (checked) {
      temp_menuCommonList.value = checked;
      setups.root.$nextTick(() => {
        temp_currentMenuId.value = 0; //重置选中菜单及其勾选值。
        common.checkedGroup = [];
      });
    }
  });

  const funcList = [
    {
      label: "新增",
      value: 1,
    },
    {
      label: "修改",
      value: 2,
    },
    {
      label: "查看",
      value: 3,
    },
    {
      label: "删除",
      value: 4,
    },
    {
      label: "导出表格",
      value: 5,
    },
  ];

  return {
    common,
    common2: {
      handleCheckAllChange,
      funcList,
      checkboxGroupChange,
    },
  };
}

/** 自定义权限列表card的功能 */
function useCustom(setups) {
  const custom = reactive({
    /** 该菜单的自定义权限列表，从后台获取 */
    custom_perm_list: [],
    /** 该菜单选中的list */
    checkedGroup: [],
    /** 缓存选中的菜单 */
    temp_menuid: 0,
    /** 缓存根据菜单，选中的选项。 */
    temp_menuCustomPermList: {},
  });
  setups.that.$on(events.menu_tree_click, (node) => {
    if (node.children) {
      custom.checkedGroup = []; //若非页面菜单，则清空列表。
      custom.custom_perm_list = [];
    } else {
      custom.temp_menuid = node.route_id;
      svs_sys_perm.getListByMenuId(node.route_id).then((res) => {
        // console.log(res);
        custom.custom_perm_list = res;
        custom.checkedGroup =
          custom.temp_menuCustomPermList[custom.temp_menuid] || [];
      });
    }
  });

  watch(
    () => custom.checkedGroup,
    (nv) => {
      if (custom.temp_menuid) {
        custom.temp_menuCustomPermList[custom.temp_menuid] = nv;
        setups.that.$emit(events.custom_check, custom.temp_menuCustomPermList);
      }
    }
  );

  setups.that.$on(events.set_checkedList, (data) => {
    const checked = data.customList;
    if (checked) {
      custom.temp_menuCustomPermList = checked;
      setups.root.$nextTick(() => {
        custom.temp_menuid = 0;
        custom.checkedGroup = [];
      });
    }
  });

  return {
    custom,
  };
}

export default {
  name: "permission-select-pannel",
  props: {},
  setup(props, ctx) {
    const setups = {
      props,
      ctx,
      root: ctx.root,
      that: getCurrentInstance(),
    };

    return useEnter(setups);
  },
};
</script>
 
 <style scoped>
.common-checkbox {
  width: 100%;
  margin: 3px 0;
}
</style>
